package com.example.musicplayer.service;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.List;
import java.util.Random;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;

import com.example.musicplayer.R;
import com.example.musicplayer.dao.IMusicHandler;
import com.example.musicplayer.dao.MusicHandler;
import com.example.musicplayer.dto.Song;
import com.example.musicplayer.exception.NoMusicFound;
import com.example.musicplayer.ui.MainMusicPlayerActivity;

/**
 * Class for methods to play music also other logic, skip, repeat, progress, etc
 * 
 */
public class MusicServiceStub extends Service implements IMusicService, MediaPlayer.OnCompletionListener {

	// Use Android media player
	MediaPlayer mp;
	List<Song> songList;
	IMusicHandler mHandler;
	NotificationManager mNotificationManager;
	NotificationCompat.Builder mNotification;
    final int NOTIFICATION_ID = 1;
    State mState = State.Retrieving;
    Context context = this;
    Bitmap thumbnail;
    private final IBinder mBinder = new LocalBinder();
    private String currentlyPlayingSongTitle;
    private String currentlyPlayingsongArtist;
    private Long currentlyPlayingalbumID;

	enum State {
        Retrieving, // Retrieving music
        Stopped,    // Stopped and not prepared to play
        Preparing,  // Preparing...
        Playing,    // Playback active
        Paused      // Playback paused
    };
    
	//string used to start service from list activity
	 public static final String ACTION_TOGGLE_PLAYBACK = "com.example.android.musicplayer.action.SONGTOBEPLAYED";
	 public static final String ACTION_PLAY = "com.example.android.musicplayer.action.PLAY";
	 public static final String ACTION_PAUSE = "com.example.android.musicplayer.action.PAUSE";
	 public static final String ACTION_FORWARD = "com.example.android.musicplayer.action.FORWARD";
	 public static final String ACTION_BACKWARD = "com.example.android.musicplayer.action.BACKWARD";
	 public static final String ACTION_STOP = "com.example.android.musicplayer.action.STOP";
	 public static final String ACTION_SHUFFLE = "com.example.android.musicplayer.action.SHUFFLE";
	 public static final String ACTION_REPEAT = "com.example.android.musicplayer.action.REPEAT";
	 public static final String ACTION_SONG_SELECTED = "com.example.android.musicplayer.action.SONG_SELECTED";
	 public static final String UPDATE_UI = "com.example.android.musicplayer.action.UPDATE_UI";
 
	 public String getCurrentlyPlayingSongTitle() {
			return currentlyPlayingSongTitle;
		}

		public void setCurrentlyPlayingSongTitle(String currentlyPlayingSongTitle) {
			this.currentlyPlayingSongTitle = currentlyPlayingSongTitle;
		}

		public String getCurrentlyPlayingsongArtist() {
			return currentlyPlayingsongArtist;
		}

		public void setCurrentlyPlayingsongArtist(String currentlyPlayingsongArtist) {
			this.currentlyPlayingsongArtist = currentlyPlayingsongArtist;
		}

		public Long getCurrentlyPlayingalbumID() {
			return currentlyPlayingalbumID;
		}

		public void setCurrentlyPlayingalbumID(Long currentlyPlayingalbumID) {
			this.currentlyPlayingalbumID = currentlyPlayingalbumID;
		}

		/**
		  * sets the strings that will be used to update UI
		  * @param song
		  */
		 private void setPlayingSongInfo(Song song){
			 setCurrentlyPlayingSongTitle(song.getSongName());
			 setCurrentlyPlayingsongArtist(song.getSongArtist());
			 setCurrentlyPlayingalbumID(song.getAlbumID());
		 }
	 
	@Override
	public void onCreate() {
		mp = new MediaPlayer();
		mHandler = new MusicHandler(getContentResolver(),false, this);
		 
        mNotificationManager = 
        		  (NotificationManager) getSystemService(NOTIFICATION_SERVICE);	
		
		try {
			songList = mHandler.GetMusicList();
		} catch (NoMusicFound e) {
			Log.e("No Music", "No music found on device");
			Toast.makeText(this,R.string.no_music, Toast.LENGTH_SHORT).show();
			onDestroy();
		}
		preparePlayer();
	}

	int songIndex = 0;
	boolean isShuffle = false;
	boolean isRepeat = false;
	 
	 
	/**
	 * Method to play music, takes SongIndex
	 */
	public void playMusic(int songIndex) {
		try {
			mp.reset();
			Song song = songList.get(songIndex);
			mp.setDataSource(song.getSongPath());
			mp.prepare();
			mp.start();
			mp.setOnCompletionListener(this);
			// Set State
			mState = State.Playing;
			setPlayingSongInfo(song);
			sendBroadcastToUpdateUI();
			// UI - set some label equal to songTitle
			showNotification(getCurrentlyPlayingSongTitle() + " (playing)");
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	@Override
    public void sendBroadcastToUpdateUI() {
    	Intent updateUiIntent = new Intent("UpDateUI.action");
		sendBroadcast(updateUiIntent);
		
	}

    @Override
	public void preparePlayer() {
		Song song = songList.get(songIndex);
		setPlayingSongInfo(song);
	}


	void showNotification(String text) {
    	Uri uri = Uri.parse(mHandler.RetrieveAlbumArt(getCurrentlyPlayingalbumID()));
		try {
			InputStream inputStream = getContentResolver().openInputStream(uri);
			thumbnail = BitmapFactory.decodeStream(inputStream);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
        PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0,
                new Intent(getApplicationContext(), MainMusicPlayerActivity.class),
                PendingIntent.FLAG_UPDATE_CURRENT);
        //intents that handles backwards/forwards/playing functions
        Intent skipBackwardsIntent = new Intent(getApplicationContext(), MusicServiceStub.class);
        skipBackwardsIntent.setAction(MusicServiceStub.ACTION_BACKWARD);
        PendingIntent skipBackwardsPendingIntent = PendingIntent.getService(getApplicationContext(), 0, skipBackwardsIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        //intents that handles backwards/forwards/playing functions
        Intent skipForwardIntent = new Intent(getApplicationContext(), MusicServiceStub.class);
        skipForwardIntent.setAction(MusicServiceStub.ACTION_FORWARD);
        PendingIntent skipForwardpendingIntent = PendingIntent.getService(getApplicationContext(), 0, skipForwardIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        //intents that handles backwards/forwards/playing functions
        Intent playIntent = new Intent(getApplicationContext(), MusicServiceStub.class);
        playIntent.setAction(MusicServiceStub.ACTION_PAUSE);
        PendingIntent playPendingIntent = PendingIntent.getService(getApplicationContext(), 0, playIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        mNotification = new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.play)
        .setContentTitle("Music Player")
        .setContentText(text)
        .setLargeIcon(thumbnail)
        .setContentIntent(pi)
        .setOngoing(true)
        .setAutoCancel(false)
        .addAction(R.drawable.back, "", skipBackwardsPendingIntent)
        .addAction(R.drawable.pause, "", playPendingIntent)
        .addAction(R.drawable.forward, "", skipForwardpendingIntent);
        
        NotificationCompat.BigTextStyle musicNotiStyle =
                new NotificationCompat.BigTextStyle();
        musicNotiStyle.setBigContentTitle("Music Player");
        musicNotiStyle.bigText(text);
        mNotification.setStyle(musicNotiStyle);
	mNotificationManager.notify(NOTIFICATION_ID , mNotification.build());

    }
	
	/**
	 * method to pause music
	 */
	public void pauseMusic() {
		mState = State.Paused;
		mp.pause();
		//clears the notification when no music is playing
		mNotificationManager.cancel(NOTIFICATION_ID);
	}

	/**
	 * method to stop music
	 */
	public void stopMusic() {
		mp.stop();
	}

	/**
	 * method to skip song
	 */
	public void skipForward() {
		//prevents music state being chagned when not playing or paused
		if(mState == State.Playing || mState == State.Paused){
			// Check if next song is there
		if (songIndex < (songList.size() - 1)) {
			playMusic(songIndex + 1);
			songIndex = songIndex + 1;
		} else {
			// play first song
			playMusic(0);
			songIndex = 0;
		}
		}
	}

	/**
	 * method to skip song backward
	 */
	public void skipBackward() {
		//prevents music state being chagned when not playing or paused
		if(mState == State.Playing || mState == State.Paused){
		// Check if song index isn't 0
		if (songIndex > 0) {
			playMusic(songIndex - 1);
			songIndex = songIndex - 1;
		} else {
			// play last song
			playMusic(songList.size() - 1);
			songIndex = songList.size() - 1;
		}
		}
	}
	

	/**
	 * method to check for song completion
	 */
	@Override
	public void onCompletion(MediaPlayer mp) {

		if (isRepeat) {
			// repeat is on play same song again
			playMusic(songIndex);
		} else if (isShuffle) {
			// shuffle is on - play a random song
			Random rand = new Random();
			songIndex = rand.nextInt((songList.size() - 1) - 0 + 1) + 0;
			playMusic(songIndex);
		} else {
			// no repeat or shuffle ON - play next song
			if (songIndex < (songList.size() - 1)) {
				playMusic(songIndex + 1);
				songIndex = songIndex + 1;
			} else {
				// play first song
				playMusic(0);
				songIndex = 0;
			}
		}
	}
	

	@Override
	public void onDestroy() {
		super.onDestroy();
	       mp.release();
	       mNotificationManager.cancel(NOTIFICATION_ID);
	}

	/**
	 * method to shuffle songs
	 */
	public void shuffle() {
		if (isShuffle) {
			isShuffle = false;
		} else {
			isShuffle = true;
			isRepeat = false;
		}
	}

	/**
	 * method to repeat song
	 */
	public void repeat() {
		if (isRepeat) {
			isRepeat = false;
			// Repeat is off
		} else {
			// make repeat to true
			isRepeat = true;
			// make shuffle to false
			isShuffle = false;
		}

	}
	
	/**
	 * Method that gets called when users is finshed listening to music
	 * will stop music and save last song played and current song play postion
	 */
	public void close(){
		stopMusic();
		//Add Save state 
	}
	
	public class LocalBinder extends Binder {
		public MusicServiceStub getService() {
            // Return this instance of LocalService so clients can call public methods
            return MusicServiceStub.this;
        }
    }
	
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return mBinder;
	}
	
	@Override
    public int onStartCommand(Intent i,int flags, int startId) {
        String action = i.getAction();
        if (action.equals(ACTION_PLAY))handlePlayRequest();
        else if (action.equals(ACTION_SONG_SELECTED))handledSelectedSong(i);
        else if (action.equals(UPDATE_UI))sendBroadcastToUpdateUI();
        else if (action.equals(ACTION_PAUSE)) pauseMusic();
        else if (action.equals(ACTION_FORWARD)) skipForward();
        else if (action.equals(ACTION_BACKWARD)) skipBackward();
        else if (action.equals(ACTION_STOP)) stopMusic();
        else if (action.equals(ACTION_REPEAT)) repeat();
        else if (action.equals(ACTION_SHUFFLE)) shuffle();
        
        return START_NOT_STICKY; 
    }

	private void handlePlayRequest() {
		if(mState == State.Retrieving)
		playMusic(songIndex);
		else{
		mp.start();	
		showNotification(getCurrentlyPlayingSongTitle()+ " (playing)");
		}
	}

	private void handledSelectedSong(Intent intent) {
		songIndex = intent.getIntExtra("songIndex", songIndex);
		playMusic(songIndex);
		
	}

}
